﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.IO;
using System.Diagnostics;
using GCPUD.Autoprov.Network;
using System.Collections;
using GCPUD.Autoprov.RemedyLib;

namespace GCPUD.AutoProv
{
    class ProvQueue
    {
        public static void DoRequest(Object oProvRequest)
        {
            if (oProvRequest == null) return;
            ProvRequest provRequest = oProvRequest as ProvRequest;

            string filename = "pancho_" + provRequest.GatewayEntry.RequestID + ".cfg";
            string path = Path.Combine(Form1.settings.provFileSaveDirectory, filename);


            Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " Working on request");
                
            bool hubIsPingable = isPingable(provRequest.HubEntry.HubIPAddress);

            string spliceinterface = "Gi" + provRequest.SplicingEntry.SwitchBlade + "/" + provRequest.SplicingEntry.SwitchPort;
          
            string interfaceVlan127 = "";
            if (hubIsPingable)
            {
                Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " " + provRequest.HubEntry.HubName + " is pingable");
                #region Hub is Pingable
                MacTableEntry macTableEntryVlan1 = new MacTableEntry(provRequest.GatewayEntry.GatewayMAC, new Vlan { VlanNum = "1" }, spliceinterface);
                MacTableEntry macTableEntryVlan127 = new MacTableEntry(provRequest.GatewayEntry.GatewayMAC, new Vlan { VlanNum = "127" }, spliceinterface);
                if (macTableEntryVlan1 != null && macTableEntryVlan127 != null)
                {
                    Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " Pinging " + provRequest.GatewayEntry.GatewayIP);
                    bool gatewayIsPingable = isPingable(IPAddress.Parse(provRequest.GatewayEntry.GatewayIP));
                    #region GatewayIsPingable
                    if (gatewayIsPingable)
                    {
                        Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + ": Gateway " + IPAddress.Parse(provRequest.GatewayEntry.GatewayIP) + " is pingable");
                        provRequest.UpdateRemedyQueue("Gateway is pingable");
                        MacTable vlan127Table = Node.GetVlanMacTable(new Vlan { VlanNum = "127" }, provRequest.HubEntry.HubIPAddress, "GrANt323");
                        interfaceVlan127 = Node.GetInterfaceName(provRequest.GatewayEntry.GatewayMAC, new Vlan { VlanNum = "127" }, provRequest.HubEntry.HubIPAddress, "GrANt323");
                        provRequest.UpdateRemedyQueue("Found on interface " + interfaceVlan127);
                        if (!(interfaceVlan127 == null) && !(spliceinterface == null) && (!interfaceVlan127.Equals(spliceinterface)))
                        {
                            Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " Wrong Interface");
                            provRequest.ProvStatus = ProvStatus.Error;
                            provRequest.FoundOnPort = interfaceVlan127;
                            provRequest.UpdateRemedyQueue("Found gateway on different port " + provRequest.FoundOnPort + ", fix port and reprovision");
                            return;
                        }
                        else
                        {
                            if (interfaceVlan127 == null || interfaceVlan127 == "")
                            {
                                provRequest.UpdateRemedyQueue("MAC not found but can ping gateway");
                                Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " Gateway Pings but can't find a MAC");
                                provRequest.ProvStatus = ProvStatus.NotFoundError;
                                return;
                            }
                        }


                        if (vlan127Table != null && vlan127Table.Contains(macTableEntryVlan127))
                        {
                            provRequest.UpdateRemedyQueue("Found on proper port. Creating config and pushing");
                            #region Configure Vlan 127 Interface

                            // Delete the file if it exists.
                            if (File.Exists(path))
                            {
                                File.Delete(path);
                            }
                            string[] privateVlans = { "280", "304", "374" };
                            string[] standardVlans = { "30", "127" };
                            List<string> vlansPrivate = new List<string>();
                            List<string> vlansNormal = new List<string>();
                            using (StreamWriter writer = File.CreateText(path))
                            {
                                foreach (ProvisioningEntry entry in provRequest.ProvEntries)
                                {
                                    AccountEntry result = provRequest.AccountEntry;


                                    if (!(vlansPrivate.Contains(entry.VlanNum)) && !(vlansNormal.Contains(entry.VlanNum)))
                                    {
                                        if (privateVlans.Contains(entry.VlanNum))
                                        {
                                            vlansPrivate.Add(entry.VlanNum);
                                        }
                                        else
                                        {
                                            vlansNormal.Add(entry.VlanNum);
                                        }
                                    }
                                }

                                writer.WriteLine("interface " + spliceinterface);
                                string configuration = "";

                                string accountAddress = provRequest.AccountEntry.AccountAddress.Trim();


                                configuration += " description " + accountAddress + " * " + provRequest.GatewayEntry.GatewayIP + " * " + provRequest.GatewayEntry.Model + " * " + System.Environment.NewLine;
                                foreach (string vlan in standardVlans)
                                {
                                    vlansNormal.Add(vlan);
                                }
                                configuration += " switchport private-vlan trunk allowed vlan ";
                                for (int i = 0; i < vlansNormal.Count; i++)
                                {
                                    configuration += vlansNormal[i];
                                    if (i != vlansNormal.Count - 1)
                                    {
                                        configuration += ",";
                                    }
                                }

                                configuration += System.Environment.NewLine;
                                if (vlansPrivate.Count > 0)
                                {
                                    foreach (string vlan in vlansPrivate)
                                    {
                                        int primaryVlan = int.Parse(vlan) + 1000;
                                        configuration += " switchport private-vlan association trunk " + primaryVlan + " " + vlan + System.Environment.NewLine;
                                    }
                                }
                                else
                                {
                                    foreach (string vlan in privateVlans)
                                    {
                                        configuration += string.Format(" no switchport private-vlan association trunk {0} {1}", int.Parse(vlan) + 1000, vlan);
                                        configuration += System.Environment.NewLine;
                                    }
                                }
                                writer.WriteLine(" no switchport trunk allowed vlan");
                                writer.WriteLine(" switchport mode private-vlan trunk");
                                writer.WriteLine(" spanning-tree portfast trunk");
                                writer.WriteLine(" no switchport block unicast");
                                writer.WriteLine(" no switchport port-security mac-address sticky");
                                writer.Write(configuration);
                                writer.WriteLine("!");
                                writer.WriteLine("end");
                                writer.Close();
                                IPAddress server = IPAddress.Parse("10.4.0.13");
                                string retVal = MoveFileToServer(path, server);

                                retVal = RunPanchoOnServer(filename, provRequest.HubEntry.HubIPAddress.ToString(), server.ToString());
                                Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " Prov Process Complete for Vlan 127:" + retVal);
                                provRequest.UpdateRemedyQueue("Hub Provisioning Complete - Port is configured");
                                Thread.Sleep(300000);
                                provRequest.ProvStatus = ProvStatus.Complete;
                            }
                            #endregion
                        }
                    }
                    #endregion

                    else
                    {
                        if (provRequest.ProvStatus == ProvStatus.NeedsVlan1Config)
                        {
                            provRequest.ProvStatus = ProvStatus.Thread;
                            provRequest.UpdateRemedyQueue("Didn't find mac on 127, Configuring interface for Vlan 1");
                            #region Configure Vlan 1 Interface
                            // Delete the file if it exists.
                            if (File.Exists(path))
                            {
                                File.Delete(path);
                            }
                            string[] privateVlans = { "280", "304", "374" };
                            string[] standardVlans = { "1", "30", "127" };
                            List<string> vlansPrivate = new List<string>();
                            List<string> vlansNormal = new List<string>();
                            using (StreamWriter writer = File.CreateText(path))
                            {

                                AccountEntry result = provRequest.AccountEntry;

                                writer.WriteLine("interface " + spliceinterface);
                                string configuration = "";

                                string accountAddress = provRequest.AccountEntry.AccountAddress.Trim();


                                configuration += " description " + accountAddress + " * " + provRequest.GatewayEntry.GatewayIP + " * " + provRequest.GatewayEntry.Model + " * Waiting for MAC on Vlan1" + System.Environment.NewLine;
                                foreach (string vlan in standardVlans)
                                {
                                    vlansNormal.Add(vlan);
                                }
                                configuration += " no switchport private-vlan trunk allowed vlan";

                                configuration += System.Environment.NewLine;
                                writer.WriteLine(" no switchport trunk allowed vlan");
                                writer.WriteLine(" spanning-tree portfast trunk");
                                writer.WriteLine(" switchport mode trunk");
                                writer.WriteLine(" no switchport block unicast");
                                writer.WriteLine(" no switchport port-security mac-address sticky");
                                writer.WriteLine(" no ip igmp snooping tcn flood");
                                writer.Write(configuration);
                                writer.WriteLine("!");
                                writer.WriteLine("end");
                                writer.Close();
                                IPAddress server = IPAddress.Parse("10.4.0.13");
                                string retVal = MoveFileToServer(path, server);

                                retVal = RunPanchoOnServer(filename, provRequest.HubEntry.HubIPAddress.ToString(), server.ToString());

                                Console.WriteLine(DateTime.Now + ":Prov Process Complete for Vlan 1:" + retVal);
                                provRequest.UpdateRemedyQueue("Configured Interface for Vlan 1, waiting 5 minutes");
                                provRequest.ProvStatus = ProvStatus.Waiting;
                                Thread.Sleep(300000);
                                provRequest.ProvStatus = ProvStatus.Working;
                                return;
                            }
                            #endregion
                        }
                        else
                        {
                            MacTable vlan1Table = Node.GetVlanMacTable(new Vlan { VlanNum = "1" }, provRequest.HubEntry.HubIPAddress, "GrANt323");
                            if (vlan1Table != null && !(vlan1Table.Contains(macTableEntryVlan1)))
                            {
                                provRequest.ProvStatus = ProvStatus.Waiting;
                                Thread.Sleep(10000);
                                provRequest.ProvStatus = ProvStatus.NeedsVlan1Config;
                                return;
                                #region Configure Vlan 1
                                //interfaceVlan1 = Node.GetInterfaceName(provRequest.GatewayEntry.GatewayMAC, new Vlan { VlanNum = "1" }, provRequest.HubEntry.HubIPAddress, "GrANt323");
                                
                                #endregion
                                //Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " Vlan 1 configured waiting 5 minutes");

                                //provRequest.UpdateRemedyQueue("Waiting 5 minutes for Vlan 1 Configuration and gateway update");

                            }
                            else
                            {
                                provRequest.UpdateRemedyQueue("Found MAC on Vlan 1, Waiting 5 minutes to configure");
                                Console.WriteLine(DateTime.Now + ":" + provRequest.Entry.RequestID + " MAC Found on Vlan 1 waiting 5 minutes");
                                provRequest.ProvStatus = ProvStatus.Waiting;
                                Thread.Sleep(300000);
                                provRequest.ProvStatus = ProvStatus.Working;
                                return;
                            }
                        }
                    }
                }
                #endregion
                else
                {
                    if (!provRequest.Problems.Contains("Hub is Down"))
                    {
                        provRequest.Problems.Add("Hub is Down");
                    }
                }

            }     

        }

        private static string RunPanchoOnServer(string filename, string hubIP, string server)
        {
            string runCommand = " -ssh -l root -pw @dmin HubProv /opt/zipp/AutoProv/runpancho '" + filename + "' '" + hubIP.ToString() + "'";
            
            string host = server.ToString();

            Process p = new Process();

            p.StartInfo.FileName = @"c:\dev\plink.exe";

            p.StartInfo.Arguments = runCommand;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.Start();
            string output = p.StandardOutput.ReadToEnd();
            string error = p.StandardError.ReadToEnd();
            p.WaitForExit();
            return output + error;
            
            
        }
        public static string MoveFileToServer(string path, IPAddress server)
        {
            Console.WriteLine(DateTime.Now + ": Moving " + path + " to server!");
            Process p = new Process();
            string arguments = "/console /command \"option batch abort\" \"option confirm off\" \"open root:@dmin@10.4.0.13\" \"cd /tftpboot/HubConfig\" \"put " + path + "\" \"exit\"";
            
            p.StartInfo.FileName = @"C:\Program Files\WinSCP\WinSCP.com";
            
            p.StartInfo.Arguments = arguments;
            p.StartInfo.CreateNoWindow = true;

            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.Start();
            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();
            return output;
        }
        public static bool isPingable(IPAddress ip)
        {
            
            int timeout = 200;

            Ping pingSender = new Ping();
            string data = "HubProvCheckingGateway";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            PingOptions options = new PingOptions(64, true);
            for (int i = 0; i < 3; i++) // try 3 times
            {
                PingReply reply = pingSender.Send(ip as IPAddress, timeout, buffer, options);

                if (reply.Status == IPStatus.Success)
                {

                    return true; //if it succeeds, we are done
                }
            }
            return false;
        }
    }
}
